#include "texture.h"
#include "terrain.h"
#include "definitions.h"
#include "toolkits/includes/glut.h"
#include "toolkits/includes/il.h"

extern unsigned int texID, ima, tHeight;
extern unsigned char *texData;
extern float *heightData;
extern float heightMap[TERRAINLENGTH*2][TERRAINLENGTH*2];
extern ILint tw, th;
extern ILint heightW, heightH;
extern Terrain *terrainClass;
extern float minHeight;
Texture::Texture() {
}

// Loads an image
void Texture::loadImage() {
	ilInit();

  loadHeightMap();

	ilGenImages(1,&ima); 
	ilBindImage(ima);

	ilLoadImage( (const ILstring) "Textures/relva.jpg");
	ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE);

	tw = ilGetInteger(IL_IMAGE_WIDTH);
	th = ilGetInteger(IL_IMAGE_HEIGHT);
	texData = ilGetData();
}

float * Texture::loadHeightMap() {
  ILubyte *heightDataTmp;
  minHeight = TERRAINHEIGHT * 1.0f;
  int x = 0, i = 0;
  // load height map
  ilGenImages(1, &tHeight);

  ilBindImage(tHeight);
  ilLoadImage((const ILstring) "Textures/terreno2.jpg");

  ilConvertImage(IL_LUMINANCE,IL_UNSIGNED_BYTE);
   
  heightW = ilGetInteger(IL_IMAGE_WIDTH);
  heightH = ilGetInteger(IL_IMAGE_HEIGHT);
  heightDataTmp = ilGetData();

  heightData = new float[heightH*heightW];
  
  for(x = 0; x < (heightW * heightH * 3); x += 3) {
    
    heightData[i] = (((heightDataTmp[i] + heightDataTmp[i+1] + heightDataTmp[i+2])/3.0f)*(float)TERRAINHEIGHT)/255.0f;
    if(heightData[i] < minHeight && heightData[i] >= 0.0f) {
      minHeight = heightData[i];
    }
    if(heightData[i] > TERRAINHEIGHT) heightData[i] = TERRAINHEIGHT; // ?
    i++;
  }
  scaleHeightMap();
  return heightData; // not necessary anymore?
}

void Texture::scaleHeightMap() {
  int i, j;

  for(i = 0; i < TERRAINLENGTH*2; i++) {
    for(j = 0; j < TERRAINLENGTH*2; j++) {
      heightMap[i][j] = getScaledHeight(i,j);
    }
  }
}

float Texture::getScaledHeight(float x, float z) {
  //x += (float)TERRAINLENGTH;
  //z += (float)TERRAINLENGTH;
  int totalLength = TERRAINLENGTH*2;

  float xFactor = (float)heightH / (float)totalLength;
  float zFactor = (float)heightW / (float)totalLength;
  float xSize = (float)totalLength / (float)heightH;
  float zSize = (float)totalLength / (float)heightW;

  int x1 = x * xFactor;
  int z1 = z * zFactor;
  int x2 = x1 + 1;
  int z2 = x2 + 2;

  int xx1, xx2, zz1, zz2;
  xx1 = x1 * xSize;
  xx2 = x2 * xSize;
  zz1 = z1 * zSize;
  zz2 = z2 * zSize;

  // Bilinear interpolation
  //http://en.wikipedia.org/wiki/Bilinear_interpolation
  // variables from wikipedia = variables from here
  // f(Q11) = terrainClass->getHeight(x1, z1)
  // x2 = xx2
  // x1 = xx1
  // x = x
  // y = y
  float height = (terrainClass->getHeight(x1, z1) / ((xx2-xx1)*(zz2-zz1))) * ((xx2-x)*(zz2-z)) + 
                 (terrainClass->getHeight(x2, z1) / ((xx2-xx1)*(zz2-zz1))) * ((x - xx1)*(zz2-z)) + 
                 (terrainClass->getHeight(x1, z2) / ((xx2-xx1)*(zz2-zz1))) * ((xx2-x)*(z-zz1)) +
                 (terrainClass->getHeight(x2, z2) / ((xx2-xx1)*(zz2-zz1))) * ((x-xx1)*(z-zz1));

  return height;
                
}

/*float *Texture::fillHeightData(float *heightData){
	ILubyte *heightDataTmp;
	int i = 0;
	float min = TERRAINHEIGHT * 1.0f;
	heightDataTmp = ilGetData();
	heightData = new float[heightH*heightW];

	for(int x = 0; x < (heightW * heightH * 3); x += 3) {
		//printf("%.2f\n",  (((heightDataTmp[x] + heightDataTmp[x+1] + heightDataTmp[x+2])/3)*(int)TERRAINHEIGHT)/255.0f);
		heightData[i] = (((heightDataTmp[i] + heightDataTmp[i+1] + heightDataTmp[i+2])/3)*TERRAINHEIGHT)/255.0f;
		if(heightData[i] < min && heightData[i] >= 0.0f) {
		  min = heightData[i];
		}
		if(heightData[i] > 30.0f) heightData[i] = 30.0f; // ?
		i++;
	}

	return heightData;
}*/

// Creates a texture from an image
void Texture::createTexture() {
	glGenTextures(1, &texID);
	glBindTexture(GL_TEXTURE_2D, texID);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData);
}